#include "console-common.h"
#include <SDL/SDL.h>
#include "lua-sub-states.h"
#include "lua-altsuspend.h"
#include "lua-conwin-altmode.h"
#include "lua-debug-funcs.h"
#include "lua-extra-attr.h"
#include <cstdio>
#include "windows.h"

#ifndef NO_LUAJIT
extern "C"
{
#ifdef LUA_R_INCL
# include "luajit.h"
#else
# include "luajit-2.0/luajit.h"
#endif
}
#endif

extern int luaevent_altkey_flags, luacon_altmenu_suspend_count;

void luacon_alt_exec_cmd_thread (lua_State * L);
int luacon_extend_str_api(lua_State *);
int luaS_userinput(lua_State *);

static void __evt_hook (lua_State * L, lua_Debug * ar)
{
	if (luaevent_altkey_flags & ALT_FUNC_LOCKING)
		luaL_error(L, "");
	return;
}

static int __luaG_msgbox (lua_State * L)
{
	const char
		*txt  = lua_tostring (L, 1),
		*capt = lua_tostring (L, 2);
	int	 typ  = lua_tointeger(L, 3);
#if defined(X86) && defined(__GNUC__)
	__asm__ __volatile__ ("lock incl %0" : "+m" (luacon_altmenu_suspend_count));
#else
	luacon_altmenu_suspend_count++;
#endif
	lua_pushinteger(L, MessageBox(NULL, txt, capt, typ));
#if defined(X86) && defined(__GNUC__)
	__asm__ __volatile__ ("lock decl %0" : "+m" (luacon_altmenu_suspend_count));
#else
	luacon_altmenu_suspend_count--;
#endif
	return 1;
}

#define ARGEXT0(NAME) {#NAME, ALT_WIN_CMD_##NAME},

static __loadconwinlibapi (lua_State * L)
{
	const static struct luaL_Reg cmd_lua_api [] = {
		{"altSuspend", luacon_altmenu_suspend},
		{"altResume", luacon_altmenu_resume},
		{"input", luaS_userinput},
		{"MessageBox", __luaG_msgbox},
		{"print", lua_write_subcon},
		{"push_message", luaQ_pushmessage},
		{"push_message_i", luaQ_pushmessagei},
		{"window", luacon_alt_exec_fnw},
		{NULL, NULL}
	};
	const static struct {const char* name; int value;} t0[] = {
		ARGEXT0(ALLOC) ARGEXT0(FREE) ARGEXT0(GET) ARGEXT0(JUMP) ARGEXT0(CHECK) ARGEXT0(VIEW) {NULL, 0}};

	luaL_register(L, "command", cmd_lua_api);
	luaL_va_setfield_ints(L, t0);
	lua_setglobal(L, "cmd");
	return 0;
}

#ifndef NO_LUAJIT
#define turn_jit_off(L, m) \
	luaJIT_setmode(L, 0, m | LUAJIT_MODE_OFF);\
	luaJIT_setmode(L, 0, m | LUAJIT_MODE_FLUSH);
#else
#define turn_jit_off(L, m) ((void)0)  /* no op! */
#endif

void read_cmd_arg(lua_State * L, char * arg, bool * k, int * f, int * p, int c, char ** v)
{
	// int i = *p;
	// UNUSED(L);
	int *cyc = luacon_blinking_period;
	lua_State * L0;
	if (*arg == '-')
	{
		arg++;
		if (!strncmp(arg, "kiosk", 6))
		{
			*k = true; SDL_ShowCursor(false);
			SDL_SetVideoMode(XRES, YRES, 32, SDL_SWSURFACE | SDL_FULLSCREEN);
		}
		else if (!strncmp(arg, "no-alt-menu", 12))
		{
			*f &= ~ALT_CAN_ENABLE;
		}
		else if (!strncmp(arg, "alt=", 4))
		{
			bool b = (arg[4] == '@');
			int n = b ? 5 : 4;
			if (arg[n] == '\0' && *p + 1 < c)
				n = 0, arg = v[++*p];
			if (~*f & ALT_FUNC_FOUND && arg[n] != '\0')
			{
				// int r;
				*f |= ALT_FUNC_FOUND;
				luacon_substates[0] = L0 = luacon_regnewstate();
				if (L0 != NULL)
				{
					luaL_openlibs(L0); // load libraries
					__loadconwinlibapi(L0);
					luacon_extend_str_api(L0);

					if (luaL_loadfile(L0, arg + n)) return;
					if (b && (lua_pcall (L0, 0, 1, 0) || lua_type(L0, -1) != LUA_TFUNCTION)) return;
					luacon_alt_func_ref_0 = luaL_ref_reg(L0);

					turn_jit_off(L0, LUAJIT_MODE_ENGINE);
					lua_sethook (L0, __evt_hook, LUA_MASKCOUNT, 200);
					HANDLE h = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)luacon_alt_exec_cmd_thread, L0, CREATE_SUSPENDED, NULL);
					luacon_alt_func_hndl_0 = (int)h;
					luacon_thread_handles.push_back(&luacon_alt_func_hndl_0);
				}
			}
		}
		else if (!strncmp(arg, "enable-blinking", 15))
		{
			if (sdl_blinking_flags_0 != NULL) goto break0;
			arg += 15;
			if (*arg == ',')
			{
				int j, k, cn;
				cn = sscanf(arg + 1, "%d,%d", &j, &k);
				(cn >= 1) && (cyc[0] = j, cyc[1] = (cn >= 2) ? k : j);
			}
			else if (*arg)
				goto break0;
			sdl_blinking_flags_0 = (BLINK_FLAGS_TYPE *) calloc(1, 2 * XCHRS * YCHRS * sizeof(BLINK_FLAGS_TYPE));
			sdl_blinking_flags_1 = sdl_blinking_flags_0 + XCHRS * YCHRS;
			sdl_blinking_flags_curr = sdl_blinking_flags_0;
		}
	}
break0: ;
	// *p = i;
}